from typing import Any

import dash
import plotly.graph_objs as go
from plotly.graph_objs.layout import Margin
from zkl_aiutils_records import NumpyRecordReader


def make_run_metric_curves(
    run_name: str,
    run_reader: NumpyRecordReader,
) -> go.Scatter | None:
    xs, ys = [], []
    for i, item in enumerate(run_reader):
        xs.append(i)
        ys.append(float(item))
    if not xs or not ys:
        return None
    return go.Scatter(x=xs, y=ys, name=run_name)


def make_runs_curve(
    runs_reader: dict[str, NumpyRecordReader],
) -> tuple[go.Scatter, ...]:
    runs_curve = []
    for run_name, run_reader in runs_reader.items():
        if run_curve := make_run_metric_curves(run_name, run_reader):
            runs_curve.append(run_curve)
    return tuple(runs_curve)


def make_metric_graph_card(
    metric: tuple[str, Any],
    runs_reader: dict[str, Any],
) -> dash.html.Div | None:
    metric_name, metric_signature = metric
    if not metric_signature.get('type') == 'ndarray':
        return None
    if not metric_signature['shape'] == ():
        return None

    curves = make_runs_curve(runs_reader)
    if not curves:
        return None

    layout = go.Layout(
        showlegend=False,
        margin=Margin(b=30, t=30, l=40, r=20))
    figure = dict(data=curves, layout=layout)
    graph = dash.dcc.Graph(figure=figure)
    return dash.html.Div(
        children=[
            dash.html.Div(metric_name,
                style={'padding': '0.3rem 0.5rem'}),
            dash.html.Div(
                style={
                    'flex': '0 0 1px',
                    'backgroundColor': '#e0e0e0',
                }),
            graph],
        style={
            'margin': '8px',
            'border': '1px solid #e0e0e0',
            'borderRadius': '4px',
            'width': '480px',
            'height': '360px',
            'display': 'flex',
            'flexDirection': 'column',
        })


def make_metrics_graph_card(
    metrics_runs_reader: dict[tuple[str, Any], dict[str, Any]],
) -> tuple[dash.html.Div, ...]:
    graphs = []
    for metric, runs_reader in metrics_runs_reader.items():
        if graph := make_metric_graph_card(metric, runs_reader):
            graphs.append(graph)
    return tuple(graphs)
